#include "Game Engine/Header/Camera.h"

Camera& GetCamera()
{
	static Camera camera;
	return camera;
}

Camera::Camera()
{
	mPosition = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	mRight    = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
	mUp       = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	mLook     = D3DXVECTOR3(0.0f, 0.0f, 1.0f);

	SetType( Free );

	D3DXMatrixIdentity(&mView);
	D3DXMatrixIdentity(&mProj);
}

Camera::~Camera()
{
}

D3DXVECTOR3& Camera::Position()
{
	return mPosition;
}

D3DXMATRIX Camera::View()const
{
	return mView;
}

D3DXMATRIX Camera::Proj()const
{
	return mProj;
}

void Camera::SetType( Type cameraType )
{
	mCameraType = cameraType;
}

void Camera::SetLens(float fovY, float aspect, float zn, float zf)
{
	D3DXMatrixPerspectiveFovLH(&mProj, fovY, aspect, zn, zf);
}

void Camera::Strafe(float d)
{
	mPosition += d*mRight;
}

void Camera::Walk(float d)
{
	mPosition += d*mLook;
}

void Camera::Pitch(float angle)
{
	D3DXMATRIX R;
	D3DXMatrixRotationAxis(&R, &mRight, angle);

	D3DXVec3TransformNormal(&mUp, &mUp, &R);
	D3DXVec3TransformNormal(&mLook, &mLook, &R);
}

void Camera::RotateY(float angle)
{
	D3DXMATRIX R;
	D3DXMatrixRotationY(&R, angle);

	D3DXVec3TransformNormal(&mRight, &mRight, &R);
	D3DXVec3TransformNormal(&mUp, &mUp, &R);
	D3DXVec3TransformNormal(&mLook, &mLook, &R);
}

void Camera::Roll( float angle )
{
	D3DXMATRIX R;
	D3DXMatrixRotationZ( &R, angle );

	D3DXVec3TransformNormal(&mRight, &mRight, &R);
	D3DXVec3TransformNormal(&mUp, &mUp, &R);
	D3DXVec3TransformNormal(&mLook, &mLook, &R);
}

void Camera::YawPitchRoll( D3DXVECTOR3 ypr )
{
	D3DXMATRIX R;
	D3DXMatrixRotationYawPitchRoll( &R, ypr.y, ypr.x, ypr.z );

	D3DXVec3TransformNormal(&mRight, &mRight, &R);
	D3DXVec3TransformNormal(&mUp, &mUp, &R);
	D3DXVec3TransformNormal(&mLook, &mLook, &R);
}

void Camera::RebuildView()
{
	// Keep camera's axes orthogonal to each other and of unit length.
	D3DXVec3Normalize(&mLook, &mLook);

	D3DXVec3Cross(&mUp, &mLook, &mRight);
	D3DXVec3Normalize(&mUp, &mUp);

	D3DXVec3Cross(&mRight, &mUp, &mLook);
	D3DXVec3Normalize(&mRight, &mRight);

	// Fill in the view matrix entries.
	float x = -D3DXVec3Dot(&mPosition, &mRight);
	float y = -D3DXVec3Dot(&mPosition, &mUp);
	float z = -D3DXVec3Dot(&mPosition, &mLook);

	mView(0,0) = mRight.x; 
	mView(1,0) = mRight.y; 
	mView(2,0) = mRight.z; 
	mView(3,0) = x;   

	mView(0,1) = mUp.x;
	mView(1,1) = mUp.y;
	mView(2,1) = mUp.z;
	mView(3,1) = y;  

	mView(0,2) = mLook.x; 
	mView(1,2) = mLook.y; 
	mView(2,2) = mLook.z; 
	mView(3,2) = z;   

	mView(0,3) = 0.0f;
	mView(1,3) = 0.0f;
	mView(2,3) = 0.0f;
	mView(3,3) = 1.0f;
}

D3DXVECTOR3& Camera::GetCameraRight()
{
	return mRight;
}

D3DXVECTOR3& Camera::GetCameraLook()
{
	return mLook;
}

D3DXVECTOR3& Camera::GetCameraUp()
{
	return mUp;
}